home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / disk / mt100.zip / MT.CPP < prev    next >
C/C++ Source or Header  |  1996-06-04  |  18KB  |  496 lines

  1. // Move To drive/directory.
  2. // Copyright 1996 Jason Hood
  3. // Started:  14 April, 1996.
  4. // Finished:  4 June.
  5.  
  6. // Will change drive as well as directory.
  7. // Allows use of slash ("/") as well as backslash ("\").
  8. // Can use multiple dots (eg. treats "..." as "../..").
  9. // Can select previous directory by using "mt;" (or "mt ;" if not so lazy).
  10. // Can also select the directory before the previous directory by using ";;".
  11. // Partial directory names, where searches always start from the root.
  12. // "mt @drives" will construct a directory structure file for drives. "mt @"
  13. // will update the directory structure file for drives already in the file.
  14. // The path is specified via mtmem. The filename is "mtdirs.dat".
  15. // Path and previous directories are stored in memory, allocated by mtmem.
  16.  
  17. // Acknowledgements: Tim Jones' WASTED.PAS for finding directories.
  18.  
  19. // You are free to use this code, or a portion thereof, as long as an
  20. // appropriate acknowledgement is made.
  21.  
  22. // Questions, suggestions and comments to hoodj@topaz.cqu.edu.au.
  23.  
  24.  
  25. #include <dir.h>
  26. #include <string.h>
  27. #include <iostream.h>
  28. #include <iomanip.h>
  29. #include <fstream.h>
  30. #include <ctype.h>
  31. #include <stdlib.h>
  32.  
  33.  
  34. #define version "1.00"
  35.  
  36. char olddir[MAXDIR], newdir[MAXDIR];    // The current and new directories
  37.  
  38. char mtdirs[MAXPATH],            // Directory structure file
  39.      prev[2][MAXDIR];            // Previous directories
  40.  
  41. char **dirs;                // Directories for each drive
  42. int dirnum;                // Number of directories on each drive
  43. const int MaxDirs = 1500;        // Maximum number of directories/drive
  44.  
  45. int find(const char* path);               // Try and find path
  46. int partdir(int num, char* partial[], char drive); // Find a partial directory
  47. void restore(char drv, const char* rev);       // Make a proper pathname
  48.  
  49. int dirfile(char* drives);        // Create directory structure for drives
  50. void finddirs(const char* startdir, const char* parent = "");// Find directories
  51. char* finddirec(struct ffblk &dir, const char* name = "");   // Find dir. name
  52. long index(ofstream& os, char drv);    // Index and write drv's directories
  53. int sort(const void* a, const void* b);    // How the directories are sorted
  54. int subs(const char* path);        // Number of directories in path
  55.  
  56. void help();                // Display help screen
  57.  
  58. inline ofstream& wlong(ofstream& os, long num) {  // Write a long to a file
  59.   os.write((char*)&num, sizeof(long));            // as a binary value
  60.   return os;
  61. }
  62.  
  63. inline ifstream& rlong(ifstream& is, long& num) { // Read a long from a file
  64.   is.read((char*)&num, sizeof(long));              // as a binary value
  65.   return is;
  66. }
  67.  
  68.  
  69. void main(int argc, char* argv[]) {
  70.  
  71.   int bprev = 1,            // Update both previous directories
  72.       result;                // Result from functions
  73.   char drive,                // Drive specified
  74.        *env;                // Environment string
  75.   unsigned mtmem = 0;            // Segment assigned by mtmem.com
  76.  
  77.   if (!(env = getenv("MTMEM")) || *env == '#') {
  78.     cout << "You must run \"MTMEM\" first." << endl;
  79.     return;
  80.   }
  81.   // Convert the string into a segment address, assuming it to be valid
  82.   for (; *env; env++) mtmem = (mtmem << 4) | (*env & 0x0f);
  83.   // It is easier to do this than to muck about with far pointers
  84.   movedata(mtmem, 0, _DS, (unsigned)mtdirs, MAXPATH+MAXDIR*2);
  85.  
  86.   olddir[0] = getdisk() + 'A';        // Retrieve the current directory
  87.   olddir[1] = ':';
  88.   olddir[2] = '\\';
  89.   getcurdir(0, olddir+3);
  90.  
  91.   if (argc == 1) {                      // No parameters
  92.     cout << endl
  93.      << "        Current directory = " << olddir << endl
  94.      << "       Previous directory = " << prev[0] << endl
  95.      << "Before previous directory = " << prev[1] << endl;
  96.     return;
  97.   }
  98.  
  99.   char *&dir = argv[1],            // Alias the first argument
  100.        &what = dir[0];            // and its first character
  101.  
  102.   if (what == '?' || dir[1] == '?') {    // First or second character help
  103.     help();
  104.     return;
  105.   }
  106.  
  107.   if (what == '@') {            // (Re)construct directory structure
  108.     result = dirfile(dir+1);
  109.     if (result) cout << "Unable to " << (result == 1 ? "create" : "open")
  110.              << " \"" << mtdirs << "\".";
  111.     return;
  112.   }
  113.  
  114.   if (what == ';') {            // Use a previous directory.
  115.     bprev = (dir[1] == ';');        // 0 - previous, 1 - before previous
  116.     strcpy(newdir, prev[bprev]);
  117.   }
  118.   else {
  119.     if (dir[1] == ':') {        // If there is a drive
  120.       newdir[0] = drive = toupper(what);
  121.       newdir[1] = ':';            // then make the new directory
  122.       newdir[2] = 0;            // start with it
  123.       dir += 2;                // and skip past it
  124.     }
  125.     else newdir[0] = drive = 0;
  126.  
  127.     if (what == '.') {            // Parent shortcut
  128.       for (int dots = 0; dir[dots] == '.'; dots++); // Count dots
  129.       if (dots > 2)            // If more than two then replace
  130.     for (int j = 0; j < dots-2; j++) { // each dot after two with "../"
  131.       strcat(newdir, "../");    // eg. replace first dot of "..." with
  132.       dir++;            // "../" to get "../.."
  133.     }
  134.     }
  135.     if (argc > 2 || !find(dir))    {    // Two parameters or an unfound subdir
  136.       result = partdir(argc-1, argv+1, drive);      // requires a search
  137.       if (result) {            // It hasn't worked
  138.     switch (result) {
  139.       case 1: cout << "Unable to open \"" << mtdirs << "\"."; break;
  140.       case 2: cout << drive << ": has not been scanned."; break;
  141.       case 3: cout << "No match found.";
  142.     }
  143.     cout << endl;
  144.     return;
  145.       }
  146.     }
  147.   }
  148.  
  149.   if (chdir(newdir) == -1) {
  150.     cout << (newdir[1] == ':' ? "Invalid drive or d" : "D")
  151.      << "irectory does not exist." << endl;
  152.     return;
  153.   }
  154.   if (newdir[1] == ':' && newdir[0] != olddir[0])
  155.     setdisk(toupper(newdir[0]) - 'A');
  156.  
  157.   // Is finding string length more efficient than copying the whole array?
  158.   movedata(_DS, (unsigned)olddir, mtmem, MAXPATH, strlen(olddir)+1);
  159.   if (bprev && strcmp(prev[0], olddir))
  160.     movedata(_DS, (unsigned)prev[0], mtmem, MAXPATH+MAXDIR, strlen(prev[0])+1);
  161. }
  162.  
  163.  
  164. // See if newdir+path exists (newdir may contain the drive). If path ends in
  165. // "*" it will select the first directory that starts with path.
  166. // Return 0 if a search for path is required, otherwise 1.
  167.  
  168. int find(const char* path) {
  169.  
  170.   int star = (path[strlen(path)-1] == '*');    // Is there a star?
  171.   struct ffblk dir;
  172.  
  173.   if (*path == 0) {            // Only a drive has been specified
  174.     newdir[2] = '.';            // So chdir will work
  175.     newdir[3] = 0;
  176.     return 1;
  177.   }
  178.  
  179.   strcat(newdir, path);
  180.   if (!finddirec(dir, newdir) &&    // The path doesn't exist,
  181.       *path != '.' && !star &&        // isn't a shortcut, doesn't end in star
  182.       !strchr(path, '/') && !strchr(path, '\\')) // and is a one name path
  183.     return 0;                // then need to search for it
  184.  
  185.   if (star) {                // Expand the name found
  186.     for (int j = strlen(newdir)-2;    // Find where the name starts
  187.        j >= 0 &&            // The very beginning or
  188.        newdir[j] != '/' &&        // after a path or
  189.        newdir[j] != '\\' &&
  190.        newdir[j] != ':';        // after the drive
  191.      j--);
  192.     strcpy(newdir+j+1, dir.ff_name);    // Replace with the actual name
  193.   }
  194.   return 1;                // Found, or not searching
  195. }
  196.  
  197.  
  198. // From the partial names try and find a match. If drive is null then search
  199. // all drives in the file. If a match is found return 0, otherwise return 1
  200. // for unable to open the file; 2 for unscanned drive; 3 for no match.
  201.  
  202. int partdir(int num, char* partial[], char drive) {
  203.  
  204.   ifstream mt(mtdirs, ios::in | ios::binary);
  205.   if (!mt) return 1;            // Bit of a problem
  206.  
  207.   char drv, let,            // Drive we're on, first letter to match
  208.        path[MAXDIR],            // A possible path
  209.        *dir;                // Subdirectory to match
  210.   long index, next = 0;            // File positions
  211.   int found;                // Pretty much self-explanatory
  212.  
  213.   for (int j = 0; j < num; j++) strupr(partial[j]);
  214.  
  215.   do {                    // For each drive required to search
  216.     mt.seekg(next);            // Point to the drive
  217.     mt.get(drv);            // Get this drive letter
  218.     rlong(mt, next);            // Pointer to next drive
  219.     if (drive) {            // Find the drive we want
  220.       while (next && drv != drive) {
  221.     mt.seekg(next);
  222.     mt.get(drv);
  223.     rlong(mt, next);
  224.       }
  225.       if (drv != drive) return 2;    // Drive not in file
  226.     }
  227.     if (isalpha(let = *partial[num-1])) {  // First name start with a letter?
  228.       mt.seekg((let-'A') * si